using System;
using System.Collections.Generic;
using System.Text;

namespace Aima.Core.Util.datastructure
{

    public class Table<TRowHeader, TColumnHeader, TValue>
    {
        private readonly List<TColumnHeader> _columnHeaders;
        private readonly List<TRowHeader> _rowHeaders;
        private readonly Dictionary<TRowHeader, Dictionary<TColumnHeader, TValue>> _rows;

        // Constructs a Table with the specified row and column headers.
	    public Table(List<TRowHeader> rowHeaders,
                     List<TColumnHeader> columnHeaders)
        {
            _rowHeaders = rowHeaders;
            _columnHeaders = columnHeaders;
            _rows = new Dictionary<TRowHeader, Dictionary<TColumnHeader, TValue>>();
            foreach (TRowHeader rowHeader in rowHeaders)
            {
                _rows.Add(rowHeader, new Dictionary<TColumnHeader, TValue>());
            }
        }

        // Maps the specified row and column to the specified value in the table.
        public void Set(TRowHeader r, TColumnHeader c, TValue v)
        {
            _rows[r].Add(c, v);
        }

        // Returns the value to which the specified row and column is mapped in this table.
        public TValue Get(TRowHeader r, TColumnHeader c)
        {
            Dictionary<TColumnHeader, TValue> rowValues = _rows[r];
            return rowValues[c];
        }


        public override String ToString()
        {
            var buf = new StringBuilder();
            foreach (TRowHeader r in _rowHeaders)
            {
                foreach (TColumnHeader c in _columnHeaders)
                {
                    buf.Append(Get(r, c).ToString());
                    buf.Append(" ");
                }
                buf.Append("\n");
            }
            return buf.ToString();
        }

        #region Nested type: Cell

        public class Cell<TValueHeader>
        {
            public Cell(TValueHeader val)
            {
                Val = val;
            }

            public TValueHeader Val { get; set; }
        }

        #endregion

        #region Nested type: Row

        public class Row<TR>
        {
            public Row()
            {
                Cells = new Dictionary<TColumnHeader, TValue>();
            }

            public Dictionary<TColumnHeader, TValue> Cells { get; set; }
        }

        #endregion
    }
}